home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / UDP.C < prev    next >
C/C++ Source or Header  |  1988-11-29  |  8KB  |  317 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "internet.h"
  7.  
  8. /* Hash table for UDP structures */
  9. struct udp_cb *udps[NUDP] = { NULLUDP} ;
  10. struct udp_stat udp_stat;    /* Statistics */
  11.  
  12. /* Create a UDP control block for lsocket, so that we can queue
  13.  * incoming datagrams.
  14.  */
  15. int
  16. open_udp(lsocket,r_upcall)
  17. struct socket *lsocket;
  18. void (*r_upcall)();
  19. {
  20.     register struct udp_cb *up;
  21.     struct udp_cb *lookup_udp();
  22.     int16 hval,hash_udp();
  23.  
  24.     if((up = lookup_udp(lsocket)) != NULLUDP)
  25.         return 0;    /* Already exists */
  26.     if((up = (struct udp_cb *)malloc(sizeof (struct udp_cb))) == NULLUDP){
  27.         net_error = NO_SPACE;
  28.         return -1;
  29.     }
  30.     up->rcvq = NULLBUF;
  31.     up->rcvcnt = 0;
  32.     up->socket.address = lsocket->address;
  33.     up->socket.port = lsocket->port;
  34.     up->r_upcall = r_upcall;
  35.  
  36.     hval = hash_udp(lsocket);
  37.     up->next = udps[hval];
  38.     up->prev = NULLUDP;
  39.     if(up->next != NULLUDP)
  40.         up->next->prev = up;
  41.     udps[hval] = up;
  42.     return 0;
  43. }
  44.  
  45. /* Send a UDP datagram */
  46. int
  47. send_udp(lsocket,fsocket,tos,ttl,bp,length,id,df)
  48. struct socket *lsocket;        /* Source socket */
  49. struct socket *fsocket;        /* Destination socket */
  50. char tos;            /* Type-of-service for IP */
  51. char ttl;            /* Time-to-live for IP */
  52. struct mbuf *bp;        /* Data field, if any */
  53. int16 length;            /* Length of data field */
  54. int16 id;            /* Optional ID field for IP */
  55. char df;            /* Don't Fragment flag for IP */
  56. {
  57.     struct mbuf *htonudp();
  58.     struct pseudo_header ph;
  59.     struct udp udp;
  60.  
  61.     length = UDPHDR;
  62.     if(bp != NULLBUF)
  63.         length += len_mbuf(bp);
  64.  
  65.     udp.source = lsocket->port;
  66.     udp.dest = fsocket->port;
  67.     udp.length = length;
  68.  
  69.     /* Create IP pseudo-header, compute checksum and send it */
  70.     ph.length = length;
  71.     ph.source = lsocket->address;
  72.     ph.dest = fsocket->address;
  73.     ph.protocol = UDP_PTCL;
  74.  
  75.     bp = htonudp(&udp,bp,&ph);
  76.     
  77.     udp_stat.sent++;
  78.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  79.     return length;
  80. }
  81.  
  82. /* Accept a waiting datagram, if available. Returns length of datagram */
  83. int
  84. recv_udp(lsocket,fsocket,bp)
  85. struct socket *lsocket;        /* Local socket to receive on */
  86. struct socket *fsocket;        /* Place to stash incoming socket */
  87. struct mbuf **bp;            /* Place to stash data packet */
  88. {
  89.     struct udp_cb *lookup_udp();
  90.     register struct udp_cb *up;
  91.     struct socket *sp;
  92.     struct mbuf *buf;
  93.     int16 length;
  94.  
  95.     up = lookup_udp(lsocket);
  96.     if(up == NULLUDP){
  97.         net_error = NO_CONN;
  98.         return -1;
  99.     }
  100.     if(up->rcvcnt == 0){
  101.         net_error = WOULDBLK;
  102.         return -1;
  103.     }
  104.     buf = dequeue(&up->rcvq);
  105.     up->rcvcnt--;
  106.  
  107.     sp = (struct socket *)buf->data;
  108.     /* Fill in the user's foreign socket structure, if given */
  109.     if(fsocket != NULLSOCK){
  110.         fsocket->address = sp->address;
  111.         fsocket->port = sp->port;
  112.     }
  113.     /* Strip socket header and hand data to user */
  114.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  115.     length = len_mbuf(buf);
  116.     if(bp != (struct mbuf **)0)
  117.         *bp = buf;
  118.     else
  119.         free_p(buf);
  120.     return length;
  121. }
  122. /* Delete a UDP control block */
  123. int
  124. del_udp(lsocket)
  125. struct socket *lsocket;
  126. {
  127.     register struct udp_cb *up;
  128.     struct udp_cb *lookup_udp();
  129.     struct mbuf *bp;
  130.     int16 hval,hash_udp();
  131.  
  132.     if((up = lookup_udp(lsocket)) == NULLUDP){
  133.         net_error = INVALID;
  134.         return -1;
  135.     }        
  136.     /* Get rid of any pending packets */
  137.     while(up->rcvcnt != 0){
  138.         bp = up->rcvq;
  139.         up->rcvq = up->rcvq->anext;
  140.         free_p(bp);
  141.         up->rcvcnt--;
  142.     }
  143.     hval = hash_udp(&up->socket);
  144.     if(udps[hval] == up){
  145.         /* First on list */
  146.         udps[hval] = up->next;
  147.         up->next->prev = NULLUDP;
  148.     } else {
  149.         up->prev->next = up->next;
  150.         up->next->prev = up->prev;
  151.     }
  152.     free((char *)up);
  153.     return 0;
  154. }
  155. /* Process an incoming UDP datagram */
  156. void
  157. udp_input(bp,protocol,source,dest,tos,length,rxbroadcast)
  158. struct mbuf *bp;
  159. char protocol;
  160. int32 source;        /* Source IP address */
  161. int32 dest;        /* Dest IP address */
  162. char tos;
  163. int16 length;
  164. char rxbroadcast;    /* The only protocol that accepts 'em */
  165. {
  166.     struct pseudo_header ph;
  167.     struct udp udp;
  168.     struct udp_cb *up,*lookup_udp();
  169.     struct socket lsocket;
  170.     struct socket *fsocket;
  171.     struct mbuf *sp;
  172.     int ckfail = 0;
  173.  
  174.     if(bp == NULLBUF)
  175.         return;
  176.  
  177.     udp_stat.rcvd++;
  178.  
  179.     /* Create pseudo-header and verify checksum */
  180.     ph.source = source;
  181.     ph.dest = dest;
  182.     ph.protocol = protocol;
  183.     ph.length = length;
  184.  
  185.     if(cksum(&ph,bp,length) != 0)
  186.         /* Checksum apparently failed, note for later */
  187.         ckfail++;
  188.  
  189.     /* Extract UDP header in host order */
  190.     ntohudp(&udp,&bp);
  191.  
  192.     /* If the checksum field is zero, then ignore a checksum error.
  193.      * I think this is dangerously wrong, but it is in the spec.
  194.      */
  195.     if(ckfail && udp.checksum != 0){
  196.         udp_stat.cksum++;
  197.         free_p(bp);
  198.         return;
  199.     }
  200.     /* If this was a broadcast packet, pretend it was sent to us */
  201.     if(rxbroadcast){
  202.         lsocket.address = ip_addr;
  203.         udp_stat.bdcsts++;
  204.     } else
  205.         lsocket.address = dest;
  206.  
  207.     lsocket.port = udp.dest;
  208.     /* See if there's somebody around to read it */
  209.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  210.         /* Nope, toss it on the floor */
  211.         udp_stat.unknown++;
  212.         free_p(bp);
  213.         return;
  214.     }
  215.     /* Create a buffer which will contain the foreign socket info */
  216.     if((sp = alloc_mbuf(sizeof(struct socket))) == NULLBUF){
  217.         /* No space, drop whole packet */
  218.         free_p(bp);
  219.         return;
  220.     }
  221.     sp->cnt = sizeof(struct socket);
  222.  
  223.     fsocket = (struct socket *)sp->data;
  224.     fsocket->address = source;
  225.     fsocket->port = udp.source;
  226.  
  227.     /* Yes, remove the now redundant UDP header, chain the foreign socket
  228.      * info in front of it and queue it
  229.      */
  230.  
  231.     sp->next = bp;
  232.     enqueue(&up->rcvq,sp);
  233.     up->rcvcnt++;
  234.     if(up->r_upcall)
  235.         (*up->r_upcall)(&lsocket,up->rcvcnt);
  236. }
  237. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  238. static
  239. struct udp_cb *
  240. lookup_udp(socket)
  241. struct socket *socket;
  242. {
  243.     register struct udp_cb *up;
  244.     int16 hash_udp();
  245.  
  246.     up = udps[hash_udp(socket)];
  247.     while(up != NULLUDP){
  248.         if(memcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  249.             break;
  250.         up = up->next;
  251.     }
  252.     return up;
  253. }
  254.  
  255. /* Hash a UDP socket (address and port) structure */
  256. static
  257. int16
  258. hash_udp(socket)
  259. struct socket *socket;
  260. {
  261.     int16 hval;
  262.  
  263.     /* Compute hash function on socket structure */
  264.     hval = hiword(socket->address);
  265.     hval ^= loword(socket->address);
  266.     hval ^= socket->port;
  267.     hval %= NUDP;
  268.     return hval;
  269. }
  270. /* Convert UDP header in internal format to an mbuf in external format */
  271. struct mbuf *
  272. htonudp(udp,bp,ph)
  273. struct udp *udp;
  274. struct mbuf *bp;
  275. struct pseudo_header *ph;
  276. {
  277.     struct mbuf *hbp;
  278.     register char *cp;
  279.     int16 checksum;
  280.  
  281.     /* Allocate UDP protocol header and fill it in */
  282.     if((hbp = alloc_mbuf(UDPHDR)) == NULLBUF){
  283.         net_error = NO_SPACE;
  284.         return NULLBUF;
  285.     }
  286.     hbp->cnt = UDPHDR;
  287.  
  288.     cp = hbp->data;
  289.     cp = put16(cp,udp->source);    /* Source port */
  290.     cp = put16(cp,udp->dest);    /* Destination port */
  291.     cp = put16(cp,udp->length);    /* Length */
  292.     *cp++ = 0;            /* Clear checksum */
  293.     *cp-- = 0;
  294.  
  295.     /* Link in the user data */
  296.     hbp->next = bp;
  297.  
  298.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  299.      * the spec requires us to change zeros into ones to distinguish an
  300.       * all-zero checksum from no checksum at all
  301.      */
  302.     if((checksum = cksum(ph,hbp,ph->length)) == 0)
  303.         checksum = 0xffff;    /* Why 32 bits if this is int16? -hyc */
  304.     put16(cp,checksum);
  305.     return hbp;
  306. }
  307. /* Convert UDP header in mbuf to internal structure */
  308. ntohudp(udp,bpp)
  309. struct udp *udp;
  310. struct mbuf **bpp;
  311. {
  312.     udp->source = pull16(bpp);
  313.     udp->dest = pull16(bpp);
  314.     udp->length = pull16(bpp);
  315.     udp->checksum = pull16(bpp);
  316. }
  317.